﻿using FFmpeg.AutoGen;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using System.Drawing.Imaging;
using SkiaSharp;
using SkiaSharp.Views.WPF;
using System.Windows.Media.Imaging;
using SkiaSharp.Views.Desktop;
using System.ComponentModel;
using System.Threading;
using System.IO;

namespace AJWPFAdmin.Core.HardwareSDKS.FFmpeg
{
    public class FFmpegRTSPCapture
    {
        private bool _stopFlag;

        public event EventHandler<Bitmap> ImageGrabbed;

        public FFmpegRTSPCapture()
        {
            _stopFlag = false;
        }

        private VideoStreamDecoder _decoder;
        private VideoFrameConverter _vfc;

        public unsafe void Start(string url)
        {
            _stopFlag = false;

            var worker = new BackgroundWorker
            {
                WorkerReportsProgress = true,
            };

            worker.DoWork += (s, e) =>
            {
                try
                {
                    _decoder = new VideoStreamDecoder(url, FFmpegUtil.HWtype);
                    var info = _decoder.GetContextInfo();

                    var sourceSize = _decoder.FrameSize;
                    var sourcePixelFormat = FFmpegUtil.HWtype == AVHWDeviceType.AV_HWDEVICE_TYPE_NONE ? _decoder.PixelFormat : GetHWPixelFormat(FFmpegUtil.HWtype);
                    var destinationSize = sourceSize;
                    var destinationPixelFormat = AVPixelFormat.AV_PIX_FMT_BGR24;

                    _vfc = new VideoFrameConverter(sourceSize, sourcePixelFormat, destinationSize, destinationPixelFormat);

                    while (!_stopFlag)
                    {
                        try
                        {
                            if (!_decoder.TryDecodeNextFrame(out var frame))
                            {
                                Thread.Sleep(1000);
                                continue;
                            }

                            var convertedFrame = _vfc.Convert(frame);
                            var bitmap = new Bitmap(convertedFrame.width, convertedFrame.height, convertedFrame.linesize[0], PixelFormat.Format24bppRgb, (IntPtr)convertedFrame.data[0]);

                            worker.ReportProgress(0, bitmap);
                        }
                        catch (Exception ex)
                        {
                            if (ex.Message.Contains("-138 occurred"))
                            {
                                e.Result = url;
                                break;
                            }
                            System.Diagnostics.Trace.WriteLine($"{url} 异常:{ex.Message}");
                            Thread.Sleep(1000);
                            continue;
                        }

                    }
                }
                catch (Exception err)
                {
                    System.Diagnostics.Trace.WriteLine($"{url} 异常:{err.Message}");
                }
                
            };

            worker.ProgressChanged += (s, e) =>
            {
                ImageGrabbed?.Invoke(this, e.UserState as Bitmap);
            };

            worker.RunWorkerCompleted += (s, e) =>
            {
                if (e.Error == null)
                {
                    _decoder?.Dispose();
                    _vfc?.Dispose();
                }
                if (e.Result is string url)
                {
                    if (!string.IsNullOrEmpty(url))
                    {
                        var timer = new System.Timers.Timer
                        {
                            Interval = TimeSpan.FromSeconds(60).TotalMilliseconds,
                            AutoReset = false
                        };
                        timer.Elapsed += (_, __) =>
                        {
                            timer.Stop();
                            Start(url);
                        };
                        timer.Start();
                    }
                }
            };

            worker.RunWorkerAsync();
        }

        private static AVPixelFormat GetHWPixelFormat(AVHWDeviceType hWDevice)
        {
            switch (hWDevice)
            {
                case AVHWDeviceType.AV_HWDEVICE_TYPE_NONE:
                    return AVPixelFormat.AV_PIX_FMT_NONE;
                case AVHWDeviceType.AV_HWDEVICE_TYPE_VDPAU:
                    return AVPixelFormat.AV_PIX_FMT_VDPAU;
                case AVHWDeviceType.AV_HWDEVICE_TYPE_CUDA:
                    return AVPixelFormat.AV_PIX_FMT_CUDA;
                case AVHWDeviceType.AV_HWDEVICE_TYPE_VAAPI:
                    return AVPixelFormat.AV_PIX_FMT_VAAPI;
                case AVHWDeviceType.AV_HWDEVICE_TYPE_DXVA2:
                    return AVPixelFormat.AV_PIX_FMT_NV12;
                case AVHWDeviceType.AV_HWDEVICE_TYPE_QSV:
                    return AVPixelFormat.AV_PIX_FMT_QSV;
                case AVHWDeviceType.AV_HWDEVICE_TYPE_VIDEOTOOLBOX:
                    return AVPixelFormat.AV_PIX_FMT_VIDEOTOOLBOX;
                case AVHWDeviceType.AV_HWDEVICE_TYPE_D3D11VA:
                    return AVPixelFormat.AV_PIX_FMT_NV12;
                case AVHWDeviceType.AV_HWDEVICE_TYPE_DRM:
                    return AVPixelFormat.AV_PIX_FMT_DRM_PRIME;
                case AVHWDeviceType.AV_HWDEVICE_TYPE_OPENCL:
                    return AVPixelFormat.AV_PIX_FMT_OPENCL;
                case AVHWDeviceType.AV_HWDEVICE_TYPE_MEDIACODEC:
                    return AVPixelFormat.AV_PIX_FMT_MEDIACODEC;
                default:
                    return AVPixelFormat.AV_PIX_FMT_NONE;
            }
        }

        public void Stop()
        {
            _stopFlag = true;
        }
    }
}
